home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
PCTV3N5
/
FPEX.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-20
|
4KB
|
121 lines
/*==================================================================
fpex.cpp -- Examples of how to use fpnum class [Listing #5]
Fixed point math
by Robert N. Goldrich
==================================================================*/
#include <iostream.h>
#include "fpnum.h"
struct point { int x, y ; } ;
struct rect {
point a, b ;
rect( int x1, int y1, int x2, int y2 )
{ a.x=x1, a.y=y1, b.x=x2, b.y=y2 ; }
} ;
struct scaler {
fpnum ax, cx, // horizontal scale factor & offset
ay, cy ; // vertical scale factor & offset
void set_scale( const rect& logical, const rect& phys ) ;
void scale( point& p ) const ;
} ;
/*------------------------------------------------------------------
xp2,yp2
+-----------------+ Physical Coordinates
| xl2,yl2 |
| |
| Logical |
| |
| xl1,yl1 |
+-----------------+
xp1,yp1
Here we want the lower-left and upper-right corners to map into one
another perfectly. Using straight fixed-point math this would not
be possible due to truncation errors. The following function
compensates for truncation errors when necessary.
------------------------------------------------------------------*/
void scaler::set_scale( const rect& p/*hys*/, const rect& l/*og*/ )
{
#define BAD_X_SCALE ( ax*dxl - dxp ).peek() // used in place of
#define BAD_Y_SCALE ( ay*dyl - dyp ).peek() // ( expression==0 )
ax = cx = ay = cy = 0 ;
int dxp = p.b.x - p.a.x ;
int dyp = p.b.y - p.a.y ;
int dxl = l.b.x - l.a.x ;
int dyl = l.b.y - l.a.y ;
if( dxp==0 || dyp==0 || dxl==0 || dyl==0 ) {
return ; // this is an error. just return
}
ax = fpnum(dxp) / dxl ; // nominal scale x
if( BAD_X_SCALE ) { // correction (see above)
int xinc = ( ( dxl < 0 ) ? -1 : 1 ) ;
ax.inc_by( xinc ) ;
}
ay = fpnum(dyp) / dyl ; // nominal scale y
if( BAD_Y_SCALE ) { // correction (see above)
int yinc = ( dyl < 0 ) ? -1 : 1 ;
ay.inc_by( yinc ) ;
}
cx = p.a.x - ax * l.a.x ; // offsets
cy = p.a.y - ay * l.a.y ;
#undef BAD_X_SCALE
#undef BAD_Y_SCALE
}
//------------------------------------------------------------------
void scaler::scale( point& p ) const
{
p.x = round_to_int( ax * p.x + cx ) ;
p.y = round_to_int( ay * p.y + cy ) ;
}
//------------------------------------------------------------------
void scale_report( const scaler& s, point p )
{
cout << "Point (" << p.x << "," << p.y ;
s.scale( p ) ;
cout << ") scales into (" << p.x << "," << p.y << ")\n" ;
}
//------------------------------------------------------------------
int main()
{
//-- Examples of how to use fpnums
fpnum fpmax ; fpmax.poke( FP_MAX ) ;
fpnum fpmin ; fpmin.poke( FP_MIN ) ;
cout << "Number of fraction bits: " << FP_FRCBITS << '\n' ;
cout << "Maximum fpnum : " << fpmax << '\n' ;
cout << "Minimum fpnum : " << fpmin << '\n' ;
cout << "--------------------------------------------------\n" ;
fpnum cc = fp_cos( 32 ) ; // cosine of 32 degrees
fpnum ss = fp_sin( 32 ) ; // sine of 32 degrees
fpnum one = cc * cc + ss * ss ; // should equal 1
cout << "This should equal 1 : " << one << " (almost!)\n" ;
cout << "The error is " << (1-one)*100 << " percent.\n" ;
cout << "--------------------------------------------------\n" ;
rect screen( 0, 0, 659, 479 ) ;
rect vport( 20, 47, 999, 600 ) ;
scaler s ;
s.set_scale( screen, vport ) ;
point p = { 20, 47 } ; scale_report( s, p ) ;
p.x = 999, p.y = 600 ; scale_report( s, p ) ;
return 0 ;
}